package com.example.publishdemo;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.InitializingBean;

import java.net.URI;
import java.util.Timer;
import java.util.TimerTask;

public class WebSocketConnector implements InitializingBean {
    private final Log logger = LogFactory.getLog(WebSocketConnector.class);

    @Override
    public void afterPropertiesSet() throws Exception {

        webSocketServerIp = null;

    }

    private WebSocketClient socketClient;
    private Timer timer;
    private String webSocketServerIp;


    private static final Object synchronizeInitSocketObject = new Object();
    private static final Object synchronizeOpenSocketConnectObject = new Object();


    public void send(String msg) throws WebSocketException {
        int connectNum = 0;
        if (socketClient == null) {
            initSocket();
        }
        if (!socketClient.isOpen()) {
            openSocketConnection();
        }
        do {
            try {
                socketClient.send(msg);
                break;
            } catch (IllegalArgumentException e) {
                throw new WebSocketException("消息参数不正确");
            } catch (WebsocketNotConnectedException e) {
                //练级关闭需要重新连接
                connectNum++;
                if (connectNum > 3) {
                    throw new WebSocketException("重试三次后依然连接不上");
                }
                try {
                    Thread.sleep(1000);
                    openSocketConnection();
                } catch (Exception e1) {
                    //todo:处理对应异常，当前应该不用处理，必要性不大
                }
            } catch (Exception e) {
                //todo:未知原因导致的异常，需要具体分析
                throw new WebSocketException("发送消息失败");
            }
        } while (true);

    }


    private void initSocket() {
        synchronized (synchronizeInitSocketObject) {
            if (socketClient != null) {
                //临界区内检测客户端是否创建，杜绝重复创建
                return;
            }
            socketClient = getSocketClient();
        }
    }


    private WebSocketClient getSocketClient() {
        URI serverUrl = null;
        return new WebSocketClient(serverUrl) {
            @Override
            public void onOpen(ServerHandshake handshakedata) {

            }

            @Override
            public void onMessage(String message) {

            }

            @Override
            public void onClose(int code, String reason, boolean remote) {

            }

            @Override
            public void onError(Exception ex) {

            }
        };
    }

    private void openSocketConnection() {
        if (socketClient == null) {
            initSocket();
        }
        if (socketClient.isOpen()) {
            return;
        }
        synchronized (synchronizeOpenSocketConnectObject) {
            if (socketClient.isOpen()) {
                //临界区判断
                return;
            }
            try {
                socketClient.connect();
                startTimer();
            } catch (IllegalStateException e) {
                closeWebsocket();
                openSocketConnection();
            }
        }
    }


    private void startTimer() {
        TimerTask timerTask = null;
        try {
            if (timer != null) {
                //取消之后不能重新开启
                timer.cancel();
                timer = null;
            }

            timer = new Timer();
            timer.schedule(timerTask, 3 * 1000, 10 * 1000);

        } catch (Exception e) {
            System.out.println(e);
        }
    }


    private void closeWebsocket() {
        //todo:通过捕捉不同异常检测到最终的关闭状态再赋值为null
        try {
            if (timer != null) {
                timer.cancel();
            }
            if (socketClient != null) {
                //该关闭方法是不加锁的，所以不知道异常抛出后是否真的关闭
                socketClient.close();
//                socketClient.closeBlocking();
            }
        } finally {
            timer = null;
            socketClient = null;
        }
    }

}
